/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#include "Shared/Auth/AuthCrypt.h"
#include <algorithm>
#include "Shared/Crypto/Hmac.h"


namespace Shared {
namespace Auth {

    AuthCrypt::AuthCrypt(void)
        : _key()
        , _send_i(0)
        , _send_j(0)
        , _recv_i(0)
        , _recv_j(0)
        , _inited(false)
    {

    }

    AuthCrypt::~AuthCrypt(void)
    {

    }

    void AuthCrypt::init(void)
    {
        _send_i = _send_j = _recv_i = _recv_j = 0;
        _inited = true;
    }

    void AuthCrypt::setKey(std::uint8_t *key, std::size_t size)
    {
        _key.resize(size);
        std::copy(key, key + size, _key.begin());
    }

    void AuthCrypt::decryptRecv(std::uint8_t *data, std::size_t size)
    {
        if (!_inited) { return; }
        if (size < CRYPTED_RECV_LEN) { return; }

        for (std::size_t t = 0; t < CRYPTED_RECV_LEN; t++)
        {
            _recv_i %= _key.size();
            std::uint8_t x = (data[t] - _recv_j) ^ _key[_recv_i];
            ++_recv_i;
            _recv_j = data[t];
            data[t] = x;
        }
    }

    void AuthCrypt::encryptSend(std::uint8_t *data, std::size_t size)
    {
        if (!_inited) { return; }
        if (size < CRYPTED_SEND_LEN) { return; }

        for (std::size_t t = 0; t < CRYPTED_SEND_LEN; t++)
        {
            _send_i %= _key.size();
            std::uint8_t x = (data[t] ^ _key[_send_i]) + _send_j;
            ++_send_i;
            data[t] = _send_j = x;
        }
    }

    void AuthCrypt::generateKey(std::uint8_t *key, Crypto::BigNumber *bn)
    {
        Shared::Crypto::HmacHash hash;
        hash.updateBigNumber(bn);
        hash.finalize();
        memcpy(key, hash.digest(), SHA_DIGEST_LENGTH);
    }

}}